package com.dhcc.bpm.modules.metadata.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dhcc.bpm.common.constant.FilePathConstant;
import com.dhcc.bpm.common.utils.DateUtils;
import com.dhcc.bpm.common.utils.JGitUtil;
import com.dhcc.bpm.common.utils.OpenapiGeneratorUtils;
import com.dhcc.bpm.modules.metadata.entity.ProdCode;
import com.dhcc.bpm.modules.metadata.service.IProdCodeService;
import com.dhcc.bpm.modules.metadata.vo.ProdCodeVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.ListBranchCommand;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.Ref;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.validation.Valid;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * 产品代码表 控制器
 *
 * @author []
 * @since 2020-06-10
 */
@RestController
@AllArgsConstructor
@NoArgsConstructor
@RequestMapping("metadata/prodcode")
@Api(value = "产品代码表", tags = "产品代码表接口")
@Slf4j
public class ProdCodeController extends BladeController {

    @Autowired
    private IProdCodeService prodCodeService;
    @Autowired
    private OpenapiGeneratorUtils openapiGeneratorUtils;
    private String prodCodePath;

    @Value("${bpm.file-public-path}")
    public void setFileUploadPath(String publicPath) {
        prodCodePath = publicPath + FilePathConstant.PRODCODEPATH;
    }

    @Value("${bpm.publicKeyvalue}")
    private String publicKeyValueSet;
    @Value("${bpm.privateKeyvalue}")
    private String privateKeyValueSet;

    /**
     * 详情
     *
     * @throws Exception
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "详情", notes = "传入prodCode")
    public R<ProdCode> detail(ProdCode prodCode) throws Exception {
        String privateKeyValue = privateKeyValueSet;
        ProdCode detail = prodCodeService.getOne(Condition.getQueryWrapper(prodCode));
        String passWord = ProdCodeController.decrypt(detail.getGitPassword(), privateKeyValue);
        detail.setGitPassword(passWord);
        return R.data(detail);
    }

    /**
     * 分页 产品代码表
     */
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "分页", notes = "传入prodCode")
    public R<IPage<ProdCode>> list(ProdCode prodCode, Query query) {
        IPage<ProdCode> pages = prodCodeService.page(Condition.getPage(query), Condition.getQueryWrapper(prodCode));
//		List<ProdCode> prodCodeList = prodCodeService.getProdCodeList(prodCode);
//		for(int i = 0; i<= prodCodeList.size(); i++) {
//			String passWord = ProdCodeController.decode(prodCodeList.get(i).getGitPassword());
//			prodCodeList.set(i, prodCode).setGitPassword(passWord);
//		}
//		for(ProdCode prodCode1 : prodCodeList) {
//			ProdCodeVO prodCodeVO = new ProdCodeVO();
//			BeanUtils.copyProperties(prodCode1, prodCodeVO);
//			((List<ProdCode>) pages).add(prodCodeVO);
//		}
        return R.data(pages);
    }

    /**
     * 自定义分页 产品代码表
     */
    @GetMapping("/page")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "分页", notes = "传入prodCode")
    public R<IPage<ProdCodeVO>> page(ProdCodeVO prodCode, Query query) {
        IPage<ProdCodeVO> pages = prodCodeService.selectProdCodePage(Condition.getPage(query), prodCode);
        return R.data(pages);
    }

    /**
     * 新增 产品代码表
     */
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "新增", notes = "传入prodCode")
    public R save(@Valid @RequestBody ProdCode prodCode) {
        return R.status(prodCodeService.save(prodCode));
    }

    /**
     * 修改 产品代码表
     */
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改", notes = "传入prodCode")
    public R update(@Valid @RequestBody ProdCode prodCode) {
        return R.status(prodCodeService.updateById(prodCode));
    }

    /**
     * 新增或修改 产品代码表
     *
     * @throws Exception
     */
    @PostMapping("/submit")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "新增或修改", notes = "传入prodCode")
    public R submit(@Valid @RequestBody ProdCode prodCode) throws Exception {

        log.info("prodCode :{}", prodCode);
        String publicKeyValue = publicKeyValueSet;
        String gitPath = prodCode.getGitAddress();
        String gitUsername = prodCode.getGituserName();
        String gitPassword = prodCode.getGitPassword();

        String path = prodCodePath;

        if (!path.endsWith("/")) {
            path = path + "/";
        }
        //本地git的路径
        String localPath;
        String[] s = gitPath.split("/");
        //代码的项目名称
        String project = s[s.length - 1].replace(".git", "");

        localPath = com.dhcc.bpm.common.utils.StringUtils.replace(path + project);

        log.info("git 项目的clone 路径为{}", localPath);

        File file = new File(localPath);
        if (file.exists()) {
            openapiGeneratorUtils.execCmd("rm -rf " + localPath);
        }

        R r = JGitUtil.setupRepository(gitUsername, gitPassword, gitPath, localPath, "develop");
        if (!r.isSuccess()) {
            return r;
        }


        String develop = "";

        Git git = null;
        try {
            git = new Git(new FileRepository(localPath + "/.git"));
            List<Ref> refs = git.branchList().setListMode(ListBranchCommand.ListMode.ALL).call();
            for (Ref ref : refs) {
                log.info("ref:{}", ref.getName());
                if (ref.getName().endsWith("/develop")) {
                    develop = "develop";
                }

            }
        } catch (Exception e) {
            log.error("查询仓库列表出错", e);
            if (!r.isSuccess()) {
                if (file.exists()) {
                    if (!file.delete()) {
                        return R.fail(r.getMsg() + ",项目清除失败!");
                    }
                }
                return r;
            }
            return R.fail(e.getMessage());
        } finally {
            if (git != null) {
                git.close();
            }
        }
        log.info("git 项目路径为{}", file.getAbsolutePath());
        if (StringUtils.isBlank(develop)) {
            log.error("develop 分支不存在");
            if (!r.isSuccess()) {
                if (file.exists()) {
                    if (!file.delete()) {
                        return R.fail(r.getMsg() + ",项目清除失败!");
                    }
                }
                return r;
            }
            return R.fail("develop 分支不存在");
        } else {
            r = JGitUtil.pull(gitUsername, gitPassword, develop, localPath);
            if (r.isSuccess()) {
                File cloneTest = new File(localPath + "/clone-test.log");
                PrintStream ps = null;
                try {
                    if (!cloneTest.exists()) {
                        cloneTest.createNewFile();
                    }
                    ps = new PrintStream(new FileOutputStream(cloneTest));
                    ps.println(DateUtils.dateTimeNow());
                    ps.flush();
                } catch (IOException e) {
                    log.info("[git仓库] 测试文件生成失败", e);
                } finally {
                    if (ps != null) {
                        ps.close();
                    }
                }
                r = JGitUtil.commitAndPush(gitUsername, gitPassword, "clone-test.log", prodCode.getProductName() + " [git仓库]测试文件创建", localPath);
            }

            if (!r.isSuccess()) {
                if (file.exists()) {
                    if (!file.delete()) {
                        return R.fail(r.getMsg() + ",项目清除失败!");
                    }
                }
                return r;
            }
        }
        gitPassword = ProdCodeController.encrypt(prodCode.getGitPassword(), publicKeyValue);
        prodCode.setGitPassword(gitPassword);
        prodCode.setGitBranch(develop);
        prodCode.setStatus(1);
        return R.status(prodCodeService.saveOrUpdate(prodCode));
    }


    /**
     * 删除 产品代码表
     */
    @PostMapping("/remove")
    @ApiOperationSupport(order = 8)
    @ApiOperation(value = "删除", notes = "传入ids")
    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
        List<ProdCode> prodCode = new ArrayList<>();
        prodCode = prodCodeService.getProdCodeName(ids);
        String gitPath = prodCode.get(0).getGitAddress();
        String path = prodCodePath;
        if (!path.endsWith("/")) {
            path = path + "/";
        }
        String localPath = ""; //本地git的路径


        String[] s = gitPath.split("/");
        //代码的项目名称
        String project = s[s.length - 1].replace(".git", "");

        localPath = path + project;

        System.out.println(project);
        System.out.println(localPath);

        File file = new File(localPath);
        if (file.exists()) {
            if (!file.delete()) {//删除失败
                log.error("清空目录失败");
            }
        }
        return R.status(prodCodeService.removeByIds(Func.toLongList(ids)));
    }

    final static Base64.Encoder encoder = Base64.getEncoder();
    final static Base64.Decoder decoder = Base64.getDecoder();

    /**
     * 给字符串加密
     *
     * @param text
     * @return
     */
    public static String encode(String text) {
        return encoder.encodeToString(text.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 将加密后的字符串进行解密
     *
     * @param encodedText
     * @return
     */
    public static String decode(String encodedText) {
        return new String(decoder.decode(encodedText), StandardCharsets.UTF_8);
    }

    //加密
    /*
     * 公钥加密
     * @Param str : 加密字符串
     * @Param publicKey : 公钥
     * return : 密文
     */
    public static String encrypt(String str, String publicKey) throws Exception {
        //base64编码的公钥
        byte[] decoded = new BASE64Decoder().decodeBuffer(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decoded);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(keySpec);

        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = new BASE64Encoder().encode(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;

    }

    /*
     * RSA私钥解密
     * @param str :加密后的字符串
     * @param privateKey : 解密后的字符串
     */
    public static String decrypt(String str, String privateKey) throws Exception {

        //64位解码加密后的字符串
        byte[] inputStr = new BASE64Decoder().decodeBuffer(new String(str.getBytes("utf-8"), "utf-8"));
        //base64解码的私钥
        byte[] decode = new BASE64Decoder().decodeBuffer(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decode);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(keySpec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputStr));
        return outStr;
    }


}
